/*
 * Copyright (c) 2022 ASR Microelectronics (Shanghai) Co., Ltd. All rights reserved.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include <stdio.h>
#include "asr_arch.h"
#include "soc_init.h"
#include "asr_wdg.h"
#include "asr_alto_boot.h"
#include "asr_flash.h"
#include "asr_common.h"
#include "systick_delay.h"
#include "lega_wlan_api.h"
#include "asr_flash_alg.h"

#if (configUSE_TICKLESS_IDLE == 1)
#include "pmu.h"
extern pmu_state_t current_state;
#endif

#define REG_AHB_BUS_CTRL   *((volatile uint32_t *)(ALWAYS_ON_REGFILE + 0x90))

/***********************************************************
* set IRQ priority not enable
*
**********************************************************/

#define NORMAL_INTCTL_PRIORITY  0

#define HWI_PRIORITY_NUM 8

/*****************************************************************************
 Function    : ArchHwiCreate
 Description : create hardware interrupt
 Input       : hwiNum       --- hwi num to create
               hwiPrio      --- priority of the hwi
               mode         --- hwi interrupt mode, between vector or non-vector
               handler      --- hwi handler
               arg          --- set trig mode of the hwi handler
                                Level Triggerred = 0
                                Postive/Rising Edge Triggered = 1
                                Negtive/Falling Edge Triggered = 3
 Output      : None
 Return      : LOS_OK on success or error code on failure

 UINT32 ArchHwiCreate(HWI_HANDLE_T hwiNum,
                                     HWI_PRIOR_T hwiPrio,
                                     HWI_MODE_T mode,
                                     HWI_PROC_FUNC handler,
                                     HWI_ARG_T arg)

int32_t ECLIC_Register_IRQ_Mode(IRQn_Type IRQn, uint8_t shv, ECLIC_TRIGGER_Type trig_mode, uint8_t lvl, uint8_t priority, void *handler)
*****************************************************************************/
extern void BLE_IRQHandler(void);

void ECLIC_Mode_Init()
{
    ArchHwiCreate(UART1_IRQn, ((INTERRUPT_LEVEL_NORMAL << HWI_PRIORITY_NUM) | NORMAL_INTCTL_PRIORITY),
        ECLIC_NON_VECTOR_INTERRUPT, UART1_IRQHandler, ECLIC_POSTIVE_EDGE_TRIGGER);

    ArchHwiCreate(UART0_IRQn, ((INTERRUPT_LEVEL_NORMAL << HWI_PRIORITY_NUM) | NORMAL_INTCTL_PRIORITY),
        ECLIC_NON_VECTOR_INTERRUPT, UART0_IRQHandler, ECLIC_POSTIVE_EDGE_TRIGGER);

    ArchHwiCreate(UART2_IRQn, ((INTERRUPT_LEVEL_NORMAL << HWI_PRIORITY_NUM) | NORMAL_INTCTL_PRIORITY),
        ECLIC_NON_VECTOR_INTERRUPT, UART2_IRQHandler, ECLIC_POSTIVE_EDGE_TRIGGER);

    ArchHwiCreate(ASRW_WI_IP_IRQn, ((INTERRUPT_LEVEL_HIGH << HWI_PRIORITY_NUM) | NORMAL_INTCTL_PRIORITY),
        ECLIC_NON_VECTOR_INTERRUPT, intc_irq, ECLIC_LEVEL_TRIGGER);

    ArchHwiCreate(D_APLL_UNLOCK_IRQn, ((INTERRUPT_LEVEL_NORMAL << HWI_PRIORITY_NUM) | NORMAL_INTCTL_PRIORITY),
        ECLIC_NON_VECTOR_INTERRUPT, D_APLL_UNLOCK_IRQHandler, ECLIC_POSTIVE_EDGE_TRIGGER);

    ArchHwiCreate(D_SX_UNLOCK_IRQn, ((INTERRUPT_LEVEL_NORMAL << HWI_PRIORITY_NUM) | NORMAL_INTCTL_PRIORITY),
        ECLIC_NON_VECTOR_INTERRUPT, D_SX_UNLOCK_IRQHandler, ECLIC_POSTIVE_EDGE_TRIGGER);

    ArchHwiCreate(WDG_IRQn, ((INTERRUPT_LEVEL_NORMAL << HWI_PRIORITY_NUM) | NORMAL_INTCTL_PRIORITY),
        ECLIC_NON_VECTOR_INTERRUPT, WDG_IRQHandler, ECLIC_POSTIVE_EDGE_TRIGGER);

    ArchHwiCreate(GPIO_IRQn, ((INTERRUPT_LEVEL_NORMAL << HWI_PRIORITY_NUM) | NORMAL_INTCTL_PRIORITY),
        ECLIC_NON_VECTOR_INTERRUPT, GPIO_IRQHandler, ECLIC_POSTIVE_EDGE_TRIGGER);

    ArchHwiCreate(TIMER_IRQn, ((INTERRUPT_LEVEL_NORMAL << HWI_PRIORITY_NUM) | NORMAL_INTCTL_PRIORITY),
        ECLIC_NON_VECTOR_INTERRUPT, TIMER_IRQHandler, ECLIC_POSTIVE_EDGE_TRIGGER);

    ArchHwiCreate(RW_BLE_IRQn, ((INTERRUPT_LEVEL_HIGHEST << HWI_PRIORITY_NUM) | NORMAL_INTCTL_PRIORITY),
        ECLIC_NON_VECTOR_INTERRUPT, BLE_IRQHandler, ECLIC_LEVEL_TRIGGER);

    ECLIC_DisableIRQ(RW_BLE_IRQn);
}

/***********************************************************
* watchdog init config
*
**********************************************************/
asr_wdg_dev_t asr_wdg;
void wdg_init(void)
{
    asr_wdg.port = 0;
    asr_wdg.config.timeout = WDG_TIMEOUT_MS;
    asr_wdg_init(&asr_wdg);
}

void flash_icache_enable(void)
{
    uint32_t temp = 0;
    REG_WR(0xE000EF50,0x0);
    temp = REG_RD(0xE000ED14);
    // bit16:d, bit17:i, 3:i+d, 2:i, 1:d
    REG_WR(0xE000ED14,temp|0x00020000);
}

void flash_dcache_enable(void)
{
    uint32_t temp = 0;
    REG_WR(0xE000EF50,0x0);
    temp = REG_RD(0xE000ED14);
    // bit16:d, bit17:i, 3:i+d, 2:i, 1:d
    REG_WR(0xE000ED14,temp|0x00030000);
}

void flash_dcache_disable(void)
{
    uint32_t temp = 0;
    REG_WR(0xE000EF50,0x0);
    temp = REG_RD(0XE000ED14) & (~0x00030000);
    // bit16:d, bit17:i, 3:i+d, 2:i, 1:d
    REG_WR(0XE000ED14, (temp | (0x00020000)));
}

uint32_t system_bus_clk  = SYSTEM_BUS_CLOCK_INIT;
uint32_t system_core_clk = SYSTEM_CORE_CLOCK_INIT;

extern void alto_drv_rco_cal(void);

/***********************************************************
*  init device: flash config,irq priority,rco and systick
*
**********************************************************/
void alto_devInit()
{
#ifdef _SPI_FLASH_ENABLE_
    asr_flash_init();
#endif
    EnableICache();
    EnableDCache();

    ECLIC_Mode_Init();
}

/**********************************************************
*  use soc_init to init board
*
**********************************************************/
int soc_init(void)
{
    alto_devInit();
    return 0;
}

void HCLK_SW_IRQHandler(void)
{
    SYS_CRM_CLR_HCLK_REC = 0x1;
}



void ahb_sync_brid_open(void)
{
    unsigned int is_using_sync_down = (REG_AHB_BUS_CTRL & (0x1<<1));
    if(!is_using_sync_down || asr_get_boot_type() == DEEP_SLEEP_RST)
    {
        // 0x40000A90 bit1 sw_use_hsync
        REG_AHB_BUS_CTRL |= (0x1<<1);
        __enable_irq();
    }
}

#if (configUSE_TICKLESS_IDLE == 1)
void enable_sleep_irq_after_deepsleep(void)
{
    if (asr_get_boot_type() == DEEP_SLEEP_RST)
    {
        // In this case means wakeup from deep sleep and need process RTC interrupt
        current_state = PMU_STATE_DEEPSLEEP;
        NVIC_ClearPendingIRQ(SLEEP_IRQn);
        NVIC_EnableIRQ(SLEEP_IRQn);
    }
}
#endif

extern void lega_reset_rw_rf(void);
extern void lega_soc_wifi_ble_clk_disable(void);
extern void lega_enable_all_soc_interrupt(void);

/*************************************************************
*  soc init config, don't run any code before it
*
**************************************************************/
int soc_pre_init(void)
{
    // enable sleep irq here to clear interrupt status after deepsleep reset
#if (configUSE_TICKLESS_IDLE == 1)
    enable_sleep_irq_after_deepsleep();
#endif

    // without bootload write LDO to 3.3V, otherwise TXPWR/EVM is bad
    REG_WR(0x40000a58,0x5FFFF);

    // enable all soc interrupt
    lega_enable_all_soc_interrupt();

    return 0;
}
